package cn.edu.jsu.official.utils;

import cn.edu.jsu.official.config.FileTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author Mo
 * @createTime 2022/3/31 20:01
 * @description
 */
@Slf4j
public class FileUtil {

    /**
     * 删除单个文件
     * @param pathName 删除文件路径名
     * @return
     */
    public static boolean deleteFile(String pathName) {
        boolean flag = false;
        File file = new File(pathName);
        if (file.isFile() && file.exists()) {
            flag = file.delete();
        }
        return flag;
    }

    /**
     * 删除目录本身以及目录下的所有文件及文件夹
     * @param pathName 目录名
     * @return
     */
    public static boolean deleteDirectory(String pathName) {
        boolean flag = false;
        File directory = new File(pathName);
        if (directory.isDirectory() && directory.exists()) {
            File[] files = directory.listFiles();
            for (File file : files) {
                if (file.isFile()) {
                    flag = deleteFile(file.getPath());
                } else {
                    flag = deleteDirectory(file.getPath());
                }
            }
            flag = directory.delete();
        }
        return flag;
    }

    /**
     * 删除文件或者目录
     * @param pathName   路径名
     * @return
     */
    public static boolean deleteDirectoryOrFile(String pathName){
        boolean flag = false;
        File file = new File(pathName);
        //如果路径是一个文件则调用deleteFiles()
        if (file.isFile()&&file.exists()){
            flag = deleteFile(pathName);
        }//如果路径是目录则调用deleteDirectory()
        else if(file.isDirectory()&&file.exists()){
            flag = deleteDirectory(pathName);
        }

        return flag;
    }

    // TODO 分界线**************************************************************************************************************

    public static void checkFile(MultipartFile multipartFile, Double fileMaxSize, List<String> fileTypeList) {
        //  1. 校验文件大小
        checkFileSize(multipartFile, fileMaxSize);

        //  2. 根据文件后缀名校验上传文件类型
        String originFileName = multipartFile.getOriginalFilename();
        if (StringUtils.isBlank(originFileName)) {
            throw new RuntimeException("FILE_NAME_IS_EMPTY");
        }
        //  获取后缀名
        String fileSuffix = originFileName.substring(originFileName.indexOf(".") + 1);
        if (!checkFileSuffix(fileSuffix, fileTypeList)) {
            throw new RuntimeException("FILE_UPLOAD_TYPE_IS_NOT_ALLOW");
        }

        //  3. 根据文件头信息校验上传文件类型
        InputStream inputStream;
        try {
            inputStream = multipartFile.getInputStream();
            //  3.1 获取文件头信息
            String fileHeaderMessage = getFileHeadMessage(inputStream);
            //  3.2 根据头文件信息修改文件的真实类型
            String fileUploadType = getFileType(fileHeaderMessage);
            if (fileUploadType == null || !checkFileSuffix(fileUploadType, fileTypeList)) {
                throw new RuntimeException("FILE_UPLOAD_TYPE_IS_NOT_ALLOWED");
            }
        } catch (IOException e) {
            log.error("上传文件失败:{}, message:{}", e, e.getMessage());
            throw new RuntimeException("FILE_UPLOAD_ERROR");
        }
    }

    /**
     * 根据文件后缀名，判断上传文件的文件类型是否被允许
     * @param fileSuffix
     * @param fileTypeList
     * @return
     */
    private static boolean checkFileSuffix(String fileSuffix, List<String> fileTypeList) {
        if (StringUtils.isBlank(fileSuffix) || CollectionUtils.isEmpty(fileTypeList)) {
            throw new RuntimeException("FILE_SUFFIX_OR_ALLOW_FILE_TYPE_IS_EMPTY");
        }
        return fileTypeList.contains(fileSuffix);
    }

    /**
     * 根据文件大小，判断上传文件的文件大小是否被允许
     * @param multipartFile  文件
     * @param fileMaxSize   允许上传文件大小的最大值
     */
    private static void checkFileSize(MultipartFile multipartFile, Double fileMaxSize) {
        long fileBytes = multipartFile.getSize();
        double fileSize = (double) fileBytes / 1048576;
        if (fileSize <= 0) {
            throw new RuntimeException("FILE_UPLOAD_EMPTY_FILE");
        } else if (fileSize > fileMaxSize) {
            throw new RuntimeException("FILE_UPLOAD_EXCEED_LIMIT");
        }
    }

    private static String getFileHeadMessage(InputStream inputStream) throws IOException {
        byte[] content = new byte[28];
        inputStream.read(content, 0, content.length);
        return byteToHexString(content);
    }

    /**
     * 文件头字节数组转为十六进制编码
     * @param content   文件头字节
     * @return  Hex编码
     */
    private static String byteToHexString(byte[] content) {
        StringBuilder builder = new StringBuilder();
        if (content == null || content.length <= 0) {
            return null;
        }
        String temp;
        for (byte b : content) {
            temp = Integer.toHexString(b & 0xFF).toUpperCase();
            if (temp.length() < 2) {
                builder.append(0);
            }
            builder.append(temp);
        }
        return builder.toString();
    }

    /**
     * 根据文件头信息获取上传文件的真实类型
     * @param fileHeaderMessage 文件头信息
     * @return  上传文件的真实信息
     */
    private static String getFileType(String fileHeaderMessage) {
        if (StringUtils.isBlank(fileHeaderMessage)) {
            return null;
        }
        fileHeaderMessage = fileHeaderMessage.toUpperCase();
        FileTypeEnum[] fileTypeEnums = FileTypeEnum.values();
        for (FileTypeEnum fileTypeEnum : fileTypeEnums) {
            if (fileHeaderMessage.startsWith(fileTypeEnum.getFileHeadMessage())) {
                return fileTypeEnum.getFileSuffix();
            }
        }
        return null;
    }
}
